//----------------------------------------------------------------------------------------------
//	Filename:	ModelTraining.h
//	Author:		Sandro Spina
//	Date:		16/01/2012
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
#pragma once

#include <boost\lexical_cast.hpp>

#include <Integrator\DepthIntegrator.h>
#include <Renderer\ScanRenderer.h>
#include <Maths\Montecarlo.h>
#include <Device\NullDevice.h>
#include <Device\BufferedImageDevice.h>
#include <Shape\KDTreeMesh.h>

#include "PointCloudSegmentation.h"

namespace Illumina
{
	namespace Core
	{
		class ModelTraining
		{
				int dbGlobalIndex;
				int dbLocalIndex;
				std::string crtActiveObjectClass;
				std::string crtActiveObjectInClass;
				std::map<std::string, std::map<std::string, PointCloudSegmentation*>*> * trained_pcs;		//map of point cloud segmentation instances. First key == generic class (e.g chairs, tables) Second key == Specific PC name (e.g. 10000, 100001, etc for chairs)
				std::map<std::string, std::pair<std::string, std::string> > primitives_obj;					//list of shape names used by primitives + type and path to model file if necessary
				std::map<std::string, KDTreeMesh*> primitive_shapes;										//map of shapes used by all primitives

			public:

				Environment * environment;															//environment used
					
				std::pair<bool, KDTreeMesh *> GetShape(std::string p_name);							//Return a reference to the kdtreemesh of p_name
				bool LoadShape(std::string p_name);													//Load shape and store it in primitive_shapes
				bool LoadAllShapes();																//Load all shapes found in primitives_obj
				bool CreateAndAddPrimitiveToSpace(std::string p_primitive_shape);					//Create Primitive and add to Environment Space	
				void AddPCS(std::string _class, std::string p_model_name, 
						PointCloudSegmentation *p_pcs);												//Add a new PointCloudSegmentation structure (p_model_name) to the DB (trained_pcs)
				void ResetDBGlobalIndex();															//ResetDBGlobalIndex to 0. Next time GetNext is called will return the first element in the DB
				void ResetDBLocalIndex();															//ResetDBLocalIndex to 0. Next time GetNext is called will return the first element in the DB
				PointCloudSegmentation * GetNext();													//Iterator for PCS instances loaded in the DB
				PointCloudSegmentation * GetNext(std::string _name);								//Iterator for PCS instances of a specific name (e.g. chairs, tables, cars, houses, etc.)
				PointCloudSegmentation * GetByName(std::string _class, std::string _name);								//Get PCS with ID.
				ModelTraining(Environment *p_environment);											//Constructor which should initialise the primitive_obj map.

				int LoadAndTrainModels(Environment* p_environment, KDTreePointCloud* p_scene, MaterialGroup * p_materialGroup);
				int LoadTrainedModels(Environment* p_environment, KDTreePointCloud* p_scene, MaterialGroup * p_materialGroup);

				void ScanModel(int p_views, std::string p_model_name, std::vector<std::vector<Vector3>> &p_scans, DepthIntegrator *p_integrator, 
									GeometricPrimitive *p_geometricPrimitive, BufferedImageDevice *p_imageDevice, Environment * p_environment);	

				void WritePointsToASCIIFile(std::vector<Vector3> * p_points, std::string _filepath, int p_i);

				void WritePointsToASCIIFile(KDTreePointCloud &p_pointCloud, std::string _filepath);	

				void ToString();

		};
	}
}